package com.zenchn.controller;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zenchn.annotation.OperLog;
import com.zenchn.aspect.utils.CriticalOperModuleEnum;
import com.zenchn.entity.HttpDataResult;
import com.zenchn.entity.JsonResult;
import com.zenchn.enums.OperLogActionEnum;
import com.zenchn.exception.CustomException;
import com.zenchn.external.service.FileGenericStrategy;
import com.zenchn.model.TSysCriticalOperatingLog;
import com.zenchn.model.TSysCriticalOperatingLogExample;
import com.zenchn.service.CriticalOperatingLogService;
import com.zenchn.utils.DateUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.xssf.usermodel.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;

/**
 * CriticalOperLogController：
 * 关键信息变更日志
 * @author dingxinfa
 * @date 2020-05-14 14:35
 */
@RestController
@RequestMapping(value = "criticalLog")
@Api(value = "关键信息变更日志", tags = "日志查询-信息变更日志")
@RequiresPermissions("report:log:critical:change:log")
public class CriticalLogController {

    private final String MODULE = "日志查询>信息变更日志";

    @Resource
    private CriticalOperatingLogService criticalOperatingLogService;

    @Resource
    private FileGenericStrategy fileGenericStrategy;


    /***
     * 业务模块列表
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.QUERY, detail = "业务模块列表")
    @ApiOperation(value = "业务模块列表", notes = "业务模块列表")
    @GetMapping(value = "/operModuleList")
    public ResponseEntity<HttpDataResult<List<String>>> operModuleList(
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpDataResult<List<String>> result = new HttpDataResult<>(request.getRequestURI());


        result.setData(CriticalOperModuleEnum.getList());
        result.setMessage("OK");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }


    /**
     * 信息变更日志分页列表
     * @param startDate
     * @param endDate
     * @param keyword
     * @param operModule
     * @param page
     * @param pageSize
     * @param request
     * @param response
     * @return
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.QUERY, detail = "信息变更日志分页列表")
    @ApiOperation(value = "信息变更日志分页列表", notes = "信息变更日志分页列表")
    @ApiImplicitParams({
            @ApiImplicitParam(dataType = "Date", name = "startDate", value = "开始时间"),
            @ApiImplicitParam(dataType = "Date", name = "endDate", value = "结束时间"),
            @ApiImplicitParam(dataType = "String", name = "keyword", value = "关键字"),
            @ApiImplicitParam(dataType = "String", name = "operModule", value = "业务模块"),
            @ApiImplicitParam(dataType = "Integer", name = "page", value = "当前第page页"),
            @ApiImplicitParam(dataType = "Integer", name = "pageSize", value = "每页pageSize数量")
    })
    @GetMapping(value = "/list")
    public ResponseEntity<HttpDataResult<PageInfo<TSysCriticalOperatingLog>>> list(
            @RequestParam(required = false, value = "startDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
            @RequestParam(required = false, value = "endDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
            @RequestParam(required = false, value = "keyword") String keyword,
            @RequestParam(required = false, value = "operModule") String operModule,
            @RequestParam(required = false, value = "page", defaultValue = "1") Integer page,
            @RequestParam(required = false, value = "pageSize", defaultValue = "10") Integer pageSize,
            HttpServletRequest request, HttpServletResponse response)throws Exception {

        HttpDataResult<PageInfo<TSysCriticalOperatingLog>> result = new HttpDataResult<>(request.getRequestURI());

        PageHelper.startPage(page, pageSize);
        PageInfo<TSysCriticalOperatingLog> pageInfo = new PageInfo<>(criticalOperatingLogService.selectByExample(packageExample(startDate,endDate,keyword,operModule)));

        result.setData(pageInfo);
        result.setMessage("获取信息变更日志分页列表");
        result.setStatus(HttpStatus.OK.value());


        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    /**
     * 组装查询条件
     * @param startDate
     * @param endDate
     * @param keyword
     * @param operModule
     * @return
     */
    private  TSysCriticalOperatingLogExample packageExample(Date startDate,Date endDate,String keyword,String operModule){
        TSysCriticalOperatingLogExample example = new TSysCriticalOperatingLogExample();

        if (!StringUtils.isEmpty(keyword)) {
            TSysCriticalOperatingLogExample.Criteria criteria = example.createCriteria();
            TSysCriticalOperatingLogExample.Criteria criteria2 = example.createCriteria();
            TSysCriticalOperatingLogExample.Criteria criteria3 = example.createCriteria();
            TSysCriticalOperatingLogExample.Criteria criteria4 = example.createCriteria();
            criteria.andOperDetailLike("%"+keyword.trim()+"%");
            criteria2.andOperActionLike("%"+keyword.trim()+"%");
            criteria3.andOperAccountLike("%"+keyword.trim()+"%");
            criteria4.andOperRealNameLike("%"+keyword.trim()+"%");
            if (null != startDate) {
                criteria.andOperTimeGreaterThanOrEqualTo(LocalDateTime.ofInstant(DateUtils.getOneDayStartTime(startDate).toInstant(), ZoneId.systemDefault()));
                criteria2.andOperTimeGreaterThanOrEqualTo(LocalDateTime.ofInstant(DateUtils.getOneDayStartTime(startDate).toInstant(), ZoneId.systemDefault()));
                criteria3.andOperTimeGreaterThanOrEqualTo(LocalDateTime.ofInstant(DateUtils.getOneDayStartTime(startDate).toInstant(), ZoneId.systemDefault()));
                criteria4.andOperTimeGreaterThanOrEqualTo(LocalDateTime.ofInstant(DateUtils.getOneDayStartTime(startDate).toInstant(), ZoneId.systemDefault()));
            }
            if (null != endDate) {
                criteria.andOperTimeLessThanOrEqualTo(LocalDateTime.ofInstant(DateUtils.getOneDayEndTime(endDate).toInstant(), ZoneId.systemDefault()));
                criteria2.andOperTimeLessThanOrEqualTo(LocalDateTime.ofInstant(DateUtils.getOneDayEndTime(endDate).toInstant(), ZoneId.systemDefault()));
                criteria3.andOperTimeLessThanOrEqualTo(LocalDateTime.ofInstant(DateUtils.getOneDayEndTime(endDate).toInstant(), ZoneId.systemDefault()));
                criteria4.andOperTimeLessThanOrEqualTo(LocalDateTime.ofInstant(DateUtils.getOneDayEndTime(endDate).toInstant(), ZoneId.systemDefault()));
            }
            if (!StringUtils.isEmpty(operModule)) {
                criteria.andOperModuleEqualTo(operModule);
                criteria2.andOperModuleEqualTo(operModule);
                criteria3.andOperModuleEqualTo(operModule);
                criteria4.andOperModuleEqualTo(operModule);
            }
            example.or(criteria2);
            example.or(criteria3);
            example.or(criteria4);

        }else {
            TSysCriticalOperatingLogExample.Criteria criteria = example.createCriteria();

            if (null != startDate) {
                criteria.andOperTimeGreaterThanOrEqualTo(LocalDateTime.ofInstant(DateUtils.getOneDayStartTime(startDate).toInstant(), ZoneId.systemDefault()));
            }
            if (null != endDate) {
                criteria.andOperTimeLessThanOrEqualTo(LocalDateTime.ofInstant(DateUtils.getOneDayEndTime(endDate).toInstant(), ZoneId.systemDefault()));
            }
            if (!StringUtils.isEmpty(operModule)) {
                criteria.andOperModuleEqualTo(operModule);
            }

        }
        example.setOrderByClause("oper_time desc");

        return  example;
    }


    /**
     * 导出信息变更日志
     * @param startDate
     * @param endDate
     * @param keyword
     * @param operModule
     * @param request
     * @param response
     * @return
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.EXPORT, detail = "导出信息变更日志")
    @ApiOperation(value = "导出信息变更日志", notes = "导出信息变更日志")
    @ApiImplicitParams({
            @ApiImplicitParam(dataType = "Date", name = "startDate", value = "开始时间"),
            @ApiImplicitParam(dataType = "Date", name = "endDate", value = "结束时间"),
            @ApiImplicitParam(dataType = "String", name = "keyword", value = "关键字"),
            @ApiImplicitParam(dataType = "String", name = "operModule", value = "业务模块"),
    })
    @GetMapping(value = "/export")
    public ResponseEntity<HttpDataResult<String>> export(
            @RequestParam(required = false, value = "startDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
            @RequestParam(required = false, value = "endDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
            @RequestParam(required = false, value = "keyword") String keyword,
            @RequestParam(required = false, value = "operModule") String operModule,
            HttpServletRequest request, HttpServletResponse response) throws Exception {

        HttpDataResult<String> result = new HttpDataResult<>(request.getRequestURI());

        List<TSysCriticalOperatingLog> logList = criticalOperatingLogService.selectByExample(packageExample(startDate,endDate,keyword,operModule));
        XSSFWorkbook wb = new XSSFWorkbook();


        if (null==logList || logList.isEmpty()){
            throw new CustomException("未查询到相关日志，无法导出！");
        }

        XSSFSheet sheet = wb.createSheet("信息更改日志");

        sheet.setColumnWidth(0, (16 * 256));
        sheet.setColumnWidth(1, (16 * 256));
        sheet.setColumnWidth(2, (80 * 256));
        sheet.setColumnWidth(3, (18 * 256));
        sheet.setColumnWidth(4, (18 * 256));
        sheet.setColumnWidth(5, (18 * 256));
        sheet.setColumnWidth(6, (18 * 256));
        sheet.setColumnWidth(7, (22 * 256));



        XSSFRow row0 = sheet.createRow(0);
        row0.setHeightInPoints(28);

        XSSFFont tableHeaderFont = wb.createFont();
        tableHeaderFont.setFontHeightInPoints((short) 12);
        tableHeaderFont.setBold(true);
        XSSFCellStyle tableHeaderStyle = wb.createCellStyle();
        tableHeaderStyle.setFont(tableHeaderFont);
        // 下边框
        tableHeaderStyle.setBorderBottom(BorderStyle.THIN);
        // 左边框
        tableHeaderStyle.setBorderLeft(BorderStyle.THIN);
        // 右边框
        tableHeaderStyle.setBorderRight(BorderStyle.THIN);
        // 上边框
        tableHeaderStyle.setBorderTop(BorderStyle.THIN);
        tableHeaderStyle.setAlignment(HorizontalAlignment.CENTER);
        tableHeaderStyle.setVerticalAlignment(VerticalAlignment.CENTER);


        createCell(row0, 0, tableHeaderStyle, "业务模块");
        createCell(row0, 1, tableHeaderStyle, "操作类型");
        createCell(row0, 2, tableHeaderStyle, "操作详情");
        createCell(row0, 3, tableHeaderStyle, "操作时间");
        createCell(row0, 4, tableHeaderStyle, "操作人账户");
        createCell(row0, 5, tableHeaderStyle, "操作人姓名");
        createCell(row0, 6, tableHeaderStyle, "访问IP");
        createCell(row0, 7, tableHeaderStyle, "访问来源");


        XSSFFont fontBody = wb.createFont();
        fontBody.setFontHeightInPoints((short) 11);
        XSSFCellStyle styleBody = wb.createCellStyle();
        styleBody.setFont(fontBody);
        // 下边框
        styleBody.setBorderBottom(BorderStyle.THIN);
        // 左边框
        styleBody.setBorderLeft(BorderStyle.THIN);
        // 右边框
        styleBody.setBorderRight(BorderStyle.THIN);
        // 上边框
        styleBody.setBorderTop(BorderStyle.THIN);
        styleBody.setAlignment(HorizontalAlignment.CENTER);
        styleBody.setVerticalAlignment(VerticalAlignment.CENTER);

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        for (int i = 0; i < logList.size(); i++) {
            TSysCriticalOperatingLog log = logList.get(i);

            XSSFRow trow = sheet.createRow(i + 1);
            trow.setHeightInPoints(24);
            createCell(trow, 0, styleBody, log.getOperModule());
            createCell(trow, 1, styleBody, log.getOperAction());
            createCell(trow, 2, styleBody, log.getOperDetail());
            createCell(trow, 3, styleBody, log.getOperTime().format(dateTimeFormatter));
            createCell(trow, 4, styleBody, log.getOperAccount());
            createCell(trow, 5, styleBody, log.getOperRealName());

            createCell(trow, 6, styleBody, log.getAccessIp());
            createCell(trow, 7, styleBody, log.getAccessLocation());
        }


        SimpleDateFormat yyyy_MM_dd = new SimpleDateFormat("yyyy-MM-dd");

        StringBuilder fileName=new StringBuilder();
        fileName.append("信息变更日志");
        if (null!=startDate){
            fileName.append("_").append(yyyy_MM_dd.format(startDate));
        }
        if (null!=endDate){
            fileName.append("_").append(yyyy_MM_dd.format(endDate));
        }
        if (!StringUtils.isEmpty(operModule)) {
            fileName.append("_").append(operModule);
        }
        if (!StringUtils.isEmpty(keyword)) {
            fileName.append("_").append(keyword);
        }

        //创建临时文件
        File excelFile = File.createTempFile(fileName.toString(), ".xlsx");

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        wb.write(baos);
        FileCopyUtils.copy(baos.toByteArray(), new FileOutputStream(excelFile));

        //保存到临时OSS上
        JsonResult<String> jsonResult = fileGenericStrategy.simpleFileUploadTempBucket("downloadExport", excelFile, fileName + ".xlsx");

        // 删除临时文件
        excelFile.delete();

        if (!jsonResult.getSuccess()) {
            throw new CustomException(jsonResult.getData().toString());
        }

        result.setData(jsonResult.getData());
        result.setMessage("OK");
        result.setStatus(HttpStatus.OK.value());


        return new ResponseEntity<>(result, HttpStatus.OK);
    }



    /**
     * 创建单元格
     *
     * @param row
     * @param column
     * @param style
     * @param value
     */
    private void createCell(XSSFRow row, int column, XSSFCellStyle style, String value) {
        XSSFCell cell = row.createCell(column);
        cell.setCellValue(new XSSFRichTextString(value));
        cell.setCellStyle(style);
    }
}
